﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Reflection;
using Core.Models;
using System.Net.Mail;
using System.Security.Cryptography;
using System.Text;
using System.Web.Routing;
using HtmlAgilityPack;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;

namespace Core
{
    public class InStrings : IRouteConstraint 
    { 
        private string[] _match = {""}; 
        public InStrings(string[] match) 
        { 
            _match = match; 
        } 
        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) 
        {
            bool fnd = false;
            string cstr = "";
            try
            {
                cstr = values[parameterName].ToString();
            }
            catch { }
            if(cstr.IndexOf(".") < 0) return false;
            string ext = cstr.Substring(cstr.IndexOf(".")+1);
            foreach (string str in _match) if (String.Compare(ext, str, true) == 0) fnd = true;
            return fnd; 
        } 
    }

    public class NameId
    {
        public string Name { get; set; }
        public string Id { get; set; }
        public NameId()
        {
            Id = "";
            Name = "";
        }
        public NameId(string pId, string pName)
        {
            Id = pId;
            Name = pName;
        }
    }

    public class EmailAddress
    {
        public string Name {get; set;}
        public string Email {get; set;}
        public EmailAddress()
        {
            Name = "";
            Email = "";
        }
        public EmailAddress(string name, string email)
        {
            Name = name;
            Email = email;
        }
    }

    public class DataTableResponse
    {
        public string sEcho {get; set;}
        public int iTotalRecords {get; set;}
        public int iTotalDisplayRecords {get; set;}
        public List<List<string>> aaData { get; set; }
        public DataTableResponse()
        {
            aaData = new List<List<string>>();
        }
    }

    public class PluginInfoForReindex
    {
        public string PluginName { get; set; }
        public string Area { get; set; }
        public string Controller { get; set; }
        public int DocumentCount { get; set; }
        public PluginInfoForReindex()
        {
            PluginName = "";
            Area = "";
            Controller = "";
            DocumentCount = 0;
        }
        public PluginInfoForReindex(string pluginname, string area, string controller, int documentcount)
        {
            PluginName = pluginname;
            Area = area;
            Controller = controller;
            DocumentCount = documentcount;
        }
    }

    public class ContainerForReindex
    {
        public int PluginCount { get; set; }
        public int TotalDocumentCount { get; set; }
        public List<PluginInfoForReindex> Plugins { get; set; }
        public ContainerForReindex()
        {
            PluginCount = 0;
            TotalDocumentCount = 0;
            Plugins = new List<PluginInfoForReindex>();
        }
    }

    public class RequireRequestValueAttribute : ActionMethodSelectorAttribute
    {
        public RequireRequestValueAttribute(string valueName)
        {
            ValueName = valueName;
        }
        public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
        {
            return (controllerContext.HttpContext.Request[ValueName] != null);
        }
        public string ValueName { get; private set; }
    }

    public static class Tools
    {
        public static string ExceptionMessage(Exception e)
        {
            string retstr = e.Message.Contains("See the inner exception for details") ? e.InnerException.Message + ", " + e.InnerException.Source + e.InnerException.StackTrace : e.Message;
            return (retstr);
        }

        public static void DebugInfo(string InfoText)
        {
            if(!String.IsNullOrEmpty(InfoText))
            {
                try
                {
                    HttpApplicationState app = HttpContext.Current.Application;
                    if ((bool)app["DebugInfo"])
                    {
                        app.Lock();
                        int seq = 1 + (int)app["DebugSequence"];
                        app["DebugSequence"] = seq;
                        app.UnLock();

                        SqlConnection cn = new SqlConnection();
                        cn.ConnectionString = ConfigurationManager.ConnectionStrings["ApplicationServices"].ToString();
                        cn.Open();
                        SqlCommand cmd = new SqlCommand();
                        cmd.Connection = cn;
                        cmd.CommandType = System.Data.CommandType.Text;
                        cmd.CommandText = "INSERT INTO Core.DebugInfo (DTStamp, Sequence, InfoText) VALUES (@DTStamp, @Sequence, @InfoText)";
                        cmd.Parameters.Clear();
                        cmd.Parameters.Add("@DTStamp", SqlDbType.DateTime).Value = DateTime.Now;
                        cmd.Parameters.Add("@Sequence", SqlDbType.Int).Value = seq;
                        cmd.Parameters.Add("@InfoText", SqlDbType.NVarChar, -1).Value = InfoText;
                        cmd.ExecuteNonQuery();
                        cn.Close();
                    }
                }
                catch (Exception e) 
                {
                    Tools.DebugInfo(Tools.ExceptionMessage(e));
                }
            }
        }

        public static string GetTextFromHtml(string htmlcontent)
        {
            string retval = "";
            if (!String.IsNullOrEmpty(htmlcontent))
            {
                HtmlDocument doc = new HtmlDocument();
                doc.LoadHtml(htmlcontent);
                retval = doc.DocumentNode.InnerText;
            }
            return retval;
        }

        public static List<NameId> YesNo()
        {
            List<NameId> list = new List<NameId>();
            list.Add(new NameId { Id = "Y", Name = "Yes" });
            list.Add(new NameId { Id = "N", Name = "No" });
            return list;
        }

        public static string FileSize(int size)
        {
            string retval = "";
            if (size < 1024)
                retval = String.Format("{0} bytes", size);
            else if (size < 1048576)
                retval = String.Format("{0} KB", size / 1024);
            else if (size < 1073741824)
                retval = String.Format("{0} MB", size / 1048576);
            else
                retval = String.Format("{0} MB", size / 1073741824);
            return retval;
        }

        public static string YesNo(string ynstr)
        {
            return ynstr == "Y" ? "Yes" : "No";
        }

        public static bool SendMail(Guid DomainId, string Subject, string Body, List<EmailAddress> To, List<EmailAddress> Cc = null, List<EmailAddress> Bcc = null, List<EmailAddress> ReplyTo = null)
        {
            // return true;
            /* Remove duplicate email addresses from the Cc list */
            if(Cc != null)
            foreach (EmailAddress e in Cc)
            {
                bool fnd = false;
                foreach (EmailAddress t in To)
                {
                    if (t.Email == e.Email)
                    {
                        fnd = true;
                    }
                }
                if (fnd) Cc.Remove(e);
            }
            /* Remove duplicates from Bcc list */
            if(Bcc != null)
            foreach (EmailAddress e in Bcc)
            {
                bool fnd = false;
                foreach (EmailAddress t in To)
                {
                    if (t.Email == e.Email)
                    {
                        fnd = true;
                    }
                }
                if (fnd)
                    Bcc.Remove(e);
                else
                {
                    foreach (EmailAddress t in Cc)
                    {
                        if (t.Email == e.Email)
                        {
                            fnd = true;
                        }
                    }
                    if (fnd) Bcc.Remove(e);
                }
            }

            /* Set up the MailMessage object */
            MailMessage msg = new MailMessage();
            foreach (EmailAddress e in To) msg.To.Add(new MailAddress(e.Email, e.Name));
            if(Cc != null) foreach (EmailAddress e in Cc) msg.CC.Add(new MailAddress(e.Email, e.Name));
            if(Bcc != null) foreach (EmailAddress e in Bcc) msg.Bcc.Add(new MailAddress(e.Email, e.Name));
            msg.Subject = Subject;
            msg.Body = Body;
            msg.IsBodyHtml = true;

            /* Get the SMTP settings for Domain and send out the mail */
            try
            {
                CoreEntities core = new CoreEntities();
                Domain d = core.Domains.First(m => m.DomainId == DomainId);
                msg.From = new MailAddress(d.SMTPFrom);
                if(ReplyTo != null) foreach (EmailAddress e in ReplyTo) msg.ReplyToList.Add(new MailAddress(e.Email, e.Name));
                SmtpClient c = new SmtpClient();
                c.Host = d.SMTPServer;
                c.Port = int.Parse(d.SMTPPort);
                c.EnableSsl = d.SMTPUseSSLYN == "Y" ? true : false;
                c.UseDefaultCredentials = false;
                c.Credentials = new System.Net.NetworkCredential(d.SMTPAccount, d.SMTPPassword);
                if(d.SMTPAllowSendYN == "Y") c.Send(msg);
            }
            catch
            {
                return false;
            }
            return true;
        }

        public static string RandomString(int size, bool lowerCase)
        {
            const string strg = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
            StringBuilder builder = new StringBuilder();
            Random random = new Random();
            char ch;
            for (int i = 0; i < size; i++)
            {
                ch = strg[Convert.ToInt32(Math.Floor(36 * random.NextDouble()))];
                builder.Append(ch);
            }
            if (lowerCase)
                return builder.ToString().ToLower();
            return builder.ToString();
        }


    }

    public static class UserPermissions
    {
        public static bool HasPermission(string PermissionName)
        {
            if (String.Compare(PermissionName, "Can Use Anonymously", true) == 0) return true;
            if (!HttpContext.Current.User.Identity.IsAuthenticated) return false;
            Guid UserId = new Guid(HttpContext.Current.User.Identity.Name);
            CoreEntities core = new CoreEntities();
            Guid PermissionId = Guid.Empty;
            try
            {
                PermissionId = core.Permissions.First(m => m.Name == PermissionName).PermissionId;
            }
            catch { }
            if (PermissionId.Equals(Guid.Empty)) return false;
            int c = core.Authorizations.Where(m => (m.UserId == UserId && m.PermissionId == PermissionId)).Count();
            if (c > 0) return true;
            List<Role> roles = core.Permissions.First(m => m.PermissionId == PermissionId).Roles.ToList();
            List<Authorization> auth = core.Authorizations.Where(a => (a.UserId == UserId && a.RoleId != null)).ToList();
            bool fnd = false;
            foreach (Role r in roles)
            {
                foreach (Authorization a in auth)
                {
                    if (a.RoleId.Equals(r.RoleId)) return true;
                }
            }
            return fnd;
        }
    }

    public class PermissionAttribute : AuthorizeAttribute
    {
        public string ValueName { get; private set; }
        public PermissionAttribute(string PermissionName)
        {
            ValueName = PermissionName;
        }
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            // The action filter logic.
            if (ValueName.IndexOf(",") > 0)
            {
                string sep = ",";
                char[] seps = sep.ToCharArray();
                List<string> permissions = ValueName.Split(seps, StringSplitOptions.RemoveEmptyEntries).ToList();
                foreach (string permission in permissions)
                {
                    if(UserPermissions.HasPermission(permission)) return true;
                }
                return false;
            }
            else
                return UserPermissions.HasPermission(ValueName);
        }
    }

    
    /// <summary>
    /// A JsonResult with ContentType of text/html and the serialized object contained within textarea tags
    /// </summary>
    /// <remarks>
    /// It is not possible to upload files using the browser's XMLHttpRequest
    /// object. So the jQuery Form Plugin uses a hidden iframe element. For a
    /// JSON response, a ContentType of application/json will cause bad browser
    /// behavior so the content-type must be text/html. Browsers can behave badly
    /// if you return JSON with ContentType of text/html. So you must surround
    /// the JSON in textarea tags. All this is handled nicely in the browser
    /// by the jQuery Form Plugin. But we need to overide the default behavior
    /// of the JsonResult class in order to achieve the desired result.
    /// </remarks>
    public class FileUploadJsonResult : JsonResult
    {
        public override void ExecuteResult(ControllerContext context)
        {
            this.ContentType = "text/html";
            context.HttpContext.Response.Write("<textarea>");
            base.ExecuteResult(context);
            context.HttpContext.Response.Write("</textarea>");
        }
    }
}